/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Particle.h"
#include <math/Matrix.h>

namespace liba
{
	namespace lib3d
	{
		namespace particles
		{
			Particle::Particle()
			{
				clear();
			}

			Particle::~Particle()
			{
				clear();
			}

			void Particle::clear()
			{
				// reset particle's fields
				isAlive               = false;
				lifeTime              = 0;
				currentState.position = math::Vector3<Float>();
				currentState.scale    = math::Vector2<Float>(1, 1);
				currentState.angle    = 0;
				currentState.color    = Color(1.0f, 1.0f, 1.0f);
				currentState.alpha    = 1;
				
				// reset velocity data
				baseVelocityFrame = -1;
				nextVelocityFrame = -1;
				
				// reset alpha data
				baseAlphaFrame = -1;
				nextAlphaFrame = -1;
				
				// reset color data
				baseColorFrame = -1;
				nextColorFrame = -1;
				
				// reset size data
				baseSizeFrame = -1;
				nextSizeFrame = -1;
				
				// reset torque data
				baseTorqueFrame = -1;
				nextTorqueFrame = -1;
				
				// reset angle data
				baseAngleFrame = -1;
				nextAngleFrame = -1;

				//active = false;
				
				// kill additional data
				std::map<void*, AdditionalField>::iterator itr = _additionalData.begin();
				while(itr != _additionalData.end())
				{
					// getting field descriptor
					AdditionalField * field = &itr->second;
					
					// release data
					if(field->destructor != NULL)
						field->destructor(field->data);
					
					// next field
					++itr;
				}
				_additionalData.clear();
				
				// reset previous state
				save_state();
			}
			
			void Particle::save_state()
			{
				memcpy(&startState, &currentState, sizeof(ParticleData));
			}
			
			void Particle::set_data_for_event(void * event, void * data, bool validate, void (*destructor)(void * data))
			{
				// check if data already in field
				if(validate)
				{
					std::map<void*, AdditionalField>::iterator itr = _additionalData.find(event);
					if(itr != _additionalData.end())
					{
						// getting field descriptor
						AdditionalField * field = &itr->second;
						
						// release data
						if(field->destructor != NULL)
							field->destructor(field->data);
					}
				}
				// create field descriptor
				AdditionalField field;
				field.destructor = destructor;
				field.data       = data;
				
				// save it
				_additionalData[event] = field;
			}
			
			bool Particle::data_for_event_is_setted(void * event)
			{
				std::map<void*, AdditionalField>::iterator itr = _additionalData.find(event);
				return (itr != _additionalData.end());
			}
			
			void Particle::remove_data_for_event(void * event)
			{
				std::map<void*, AdditionalField>::iterator itr = _additionalData.find(event);
				if(itr != _additionalData.end())
					_additionalData.erase(itr);
			}
			
			void * Particle::get_data_for_event(void * event)
			{
				// check if data in array
				std::map<void*, AdditionalField>::iterator itr = _additionalData.find(event);
				if(itr != _additionalData.end())
					return itr->second.data;
				
				// nothing found
				return NULL;
			}
		}
	}
}